package com.sky.AOP;

import com.sky.anno.AutoFill;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.time.LocalDateTime;

@Aspect
@Component
public class AutoFillAspect {
    // 切入点表达式
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.anno.AutoFill)")
    public void pc(){}

    @Around("pc() && @annotation(autoFill)")
    public Object autoFill(ProceedingJoinPoint pjp, AutoFill autoFill) throws Throwable {
        //1. 获取方法参数
        Object[] args = pjp.getArgs();
        Object pojo = args[0];
        //2. 获取操作类型
        OperationType type = autoFill.value();
        //3. 判断其做的是新增还是修改
        // 先获取字节码对象, 方便对方法操作
        Class<?> c = pojo.getClass();
        // 判断在Mapper中注解是否有OperationType.INSERT(也就是新增操作)
        // 如果是新增需要设置四个参数,所以进入if执行设置两个参数后出来在设置两个参数,而修改不需要执行if里面的操作
        if (type == OperationType.INSERT){
            // 获取方法
            Field createTimeField = c.getDeclaredField("createTime");
            // 因为类型私有所以用暴力反射
            createTimeField.setAccessible(true);
            // 进行新增操作, 设置创建时间
            createTimeField.set(pojo, LocalDateTime.now());

            // 设置创建人
            Field createUserField = c.getDeclaredField("createUser");
            createUserField.setAccessible(true);
            createUserField.set(pojo, BaseContext.getCurrentId());
        }
        // 如果没进入if 说明是修改操作,只用修改两个参数即可
        Field updateTimeField = c.getDeclaredField("updateTime"); // 创建时间
        updateTimeField.setAccessible(true);
        updateTimeField.set(pojo, LocalDateTime.now());
        Field updateUserField = c.getDeclaredField("updateUser"); // 创建人ID
        updateUserField.setAccessible(true);
        updateUserField.set(pojo, BaseContext.getCurrentId());

        Object result = pjp.proceed(args);
        return result;
    }
}
